#include "glTexture.h"

#include <stdio.h>

#include "glError.h"

void glSetSampler(GLenum target, const GL_SAMPLER_DESC * pSampler)
{
    if (pSampler == NULL)
    {
			//@ set default texture sampler parameters
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		}
		else
		{        
			glTexParameteri ( target, GL_TEXTURE_WRAP_S, pSampler->AddressS );	
			glTexParameteri ( target, GL_TEXTURE_WRAP_T, pSampler->AddressT );
			glTexParameteri ( target, GL_TEXTURE_WRAP_R, pSampler->AddressR );

			glTexParameteri ( target, GL_TEXTURE_MIN_FILTER, pSampler->Filter.Min);
			glTexParameteri ( target, GL_TEXTURE_MAG_FILTER, pSampler->Filter.Mag);

			glTexParameterf ( target, GL_TEXTURE_MIN_LOD, pSampler->MinLOD);
			glTexParameterf ( target, GL_TEXTURE_MAX_LOD, pSampler->MaxLOD);

			glTexParameteri ( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, pSampler->MaxAnisotropy);

			glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, pSampler->BorderColor);

			if (pSampler->ComparisonFunc != GL_NONE)
			{
					glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB );
					glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, pSampler->ComparisonFunc );
			}
			else
					glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );

		}
}

GLint glCreateTexture( const GL_TEXTURE_DESC * pDesc, const GL_SUBRESOURCE_DATA * pSubResource, const GL_SAMPLER_DESC * pSampler)
{

    if (pDesc == NULL && pSubResource == NULL && pSampler == NULL)
        return -1;

    bool bMipmap = pDesc->MipLevels == 0;
    GLuint texID = 0;

    glGenTextures(1, &texID);
    glBindTexture(pDesc->Target, texID);
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

		if (bMipmap)
		{
			if (pDesc->Target == GL_TEXTURE_2D) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); 
		}

		glSetSampler( pDesc->Target, pSampler);

    switch(pDesc->Target)
    {
        case GL_TEXTURE_1D:            
            glTexImage1D( pDesc->Target, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Border, 
                          pSubResource->Format, pSubResource->Type, pSubResource->pSysMem);
        break;

        case GL_TEXTURE_2D:
            glTexImage2D( pDesc->Target, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->Border, 
                          pSubResource->Format, pSubResource->Type, pSubResource->pSysMem);         
            //if (bMipmap) glGenerateMipmap(GL_TEXTURE_2D);
        break;

        case GL_TEXTURE_2D_ARRAY_EXT:
            glTexImage3D( pDesc->Target, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->ArraySize, pDesc->Border, 
                          pSubResource->Format, pSubResource->Type, pSubResource->pSysMem);         
            //if (bMipmap) glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
            break;

        case GL_TEXTURE_3D:
            //glCheckError(__LINE__, "glTexture.cpp : case GL_TEXTURE_3D : start\n");
            glTexImage3D( pDesc->Target, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->Depth, pDesc->Border, 
                          pSubResource->Format, pSubResource->Type, pSubResource->pSysMem);
            //if (bMipmap) glGenerateMipmap(GL_TEXTURE_3D);
            //glCheckError(__LINE__, "glTexture.cpp : case GL_TEXTURE_3D : end  \n");
        break;

        case GL_TEXTURE_CUBE_MAP:

            glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->Border, 
                          pSubResource[0].Format, pSubResource[0].Type, pSubResource[0].pSysMem);
            glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->Border, 
                          pSubResource[1].Format, pSubResource[1].Type, pSubResource[1].pSysMem);
            glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->Border, 
                          pSubResource[2].Format, pSubResource[2].Type, pSubResource[2].pSysMem);
            glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->Border, 
                          pSubResource[3].Format, pSubResource[3].Type, pSubResource[3].pSysMem);
            glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->Border, 
                          pSubResource[4].Format, pSubResource[4].Type, pSubResource[4].pSysMem);
            glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 
                          pDesc->Format, pDesc->Width, pDesc->Height, pDesc->Border, 
                          pSubResource[5].Format, pSubResource[5].Type, pSubResource[5].pSysMem);
            glBindTexture(pDesc->Target, 0);
            //glGenerateMipmap( GL_TEXTURE_CUBE_MAP );
            break;
            
        default:
            glDeleteTextures(1, &texID);

						texID = 0;

            fprintf(stderr, "glCreateTexture() : invalid target value\n");
            break;
    }	
		glBindTexture(pDesc->Target, 0);

    return texID;
}